﻿using System;
using System.Collections;
using System.Collections.Generic;
using System.ComponentModel;
using System.Reflection;
using System.Windows.Data;
using System.Linq;
using System.Collections.Specialized;
using Gmantis.Controls.DataGrid.Data;
using System.Collections.ObjectModel;

namespace Gmantis.Controls.DataGrid
{
    internal class DataConnection
    {
        // Fields
        private IEnumerable<PropertyInfo> _dataProperties;
        private ICollectionView _dataSource;
        private Type _dataType;
        private IDisposable _deferRefreshDisposable;
        private DataGridColumnValue<DataGridFilterState>[] _desiredC1filters = new DataGridColumnValue<DataGridFilterState>[0];
        private Predicate<object> _desiredMSfilters;
        private DataGridFilterManager _filterManager;
        private DataGridGroupManager _groupManager;
        private DataGrid _owner;
        private DataGridSortManager _sortManager;

        // Events
        public event CollectionChangedEventHandler CollectionChanged;

        public event EventHandler CurrentChanged;

        public event CurrentChangingEventHandler CurrentChanging;

        // Methods
        public DataConnection(DataGrid owner, DataGridSortManager sortManager, DataGridFilterManager filterManager, DataGridGroupManager groupManager)
        {
            this._owner = owner;
            this._sortManager = sortManager;
            this._filterManager = filterManager;
            this._groupManager = groupManager;
        }

        public void AddDataItems(KeyValuePair<int, object>[] addedItems)
        {
            if (this.EditableCollectionView != null)
            {
                foreach (KeyValuePair<int, object> pair in addedItems)
                {
                    object collectionViewItem = this.EditableCollectionView.AddNew();
                    this._owner.OnCopyPropertiesBeforeAddingItem(pair.Value, collectionViewItem, this.DataProperties);
                    this.EditableCollectionView.CommitNew();
                }
            }
        }

        public void BeginEdit(object dataItem)
        {
            if (((this.CollectionView == null) || this.CollectionView.Contains(dataItem)) && (dataItem != null))
            {
                IEditableCollectionView editableCollectionView = this.EditableCollectionView;
                if (editableCollectionView != null)
                {
                    if (!editableCollectionView.IsEditingItem || (dataItem != editableCollectionView.CurrentEditItem))
                    {
                        editableCollectionView.EditItem(dataItem);
                    }
                }
                else
                {
                    IEditableObject obj2 = dataItem as IEditableObject;
                    if (obj2 != null)
                    {
                        obj2.BeginEdit();
                    }
                }
            }
        }

        public void BeginUpdate()
        {
            if (this.CollectionView != null)
            {
                this._deferRefreshDisposable = this.CollectionView.DeferRefresh();
            }
        }

        public void CancelEdit(object dataItem)
        {
            IEditableCollectionView editableCollectionView = this.EditableCollectionView;
            if (editableCollectionView != null)
            {
                if (editableCollectionView.CanCancelEdit)
                {
                    editableCollectionView.CancelEdit();
                }
                else
                {
                    editableCollectionView.CommitEdit();
                }
            }
            else
            {
                IEditableObject obj2 = dataItem as IEditableObject;
                if (obj2 != null)
                {
                    obj2.CancelEdit();
                }
            }
        }

        private void CollectionView_CurrentChanged(object sender, EventArgs e)
        {
            if (this.CurrentChanged != null)
            {
                this.CurrentChanged(sender, e);
            }
        }

        private void CollectionView_CurrentChanging(object sender, CurrentChangingEventArgs e)
        {
            if (this.CurrentChanging != null)
            {
                this.CurrentChanging(sender, e);
            }
        }

        public object CreateItem()
        {
            if (this._dataType == null)
            {
                return null;
            }
            return this._dataType.CreateInstance();
        }

        public void EndEdit(object dataItem)
        {
            IEditableCollectionView editableCollectionView = this.EditableCollectionView;
            if (editableCollectionView != null)
            {
                if (editableCollectionView.IsEditingItem)
                {
                    editableCollectionView.CommitEdit();
                }
            }
            else
            {
                IEditableObject obj2 = dataItem as IEditableObject;
                if (obj2 != null)
                {
                    obj2.EndEdit();
                }
            }
        }

        public void EndUpdate()
        {
            if (this._deferRefreshDisposable != null)
            {
                this._deferRefreshDisposable.Dispose();
                this._deferRefreshDisposable = null;
            }
        }

        public object GetDataItem(int index)
        {
            IList list = this.List;
            if (list != null)
            {
                if (index >= list.Count)
                {
                    return null;
                }
                return list[index];
            }
            PagedCollectionView dataSource = this.DataSource as PagedCollectionView;
            if (dataSource != null)
            {
                if (index >= dataSource.Count)
                {
                    return null;
                }
                return dataSource.GetItemAt(index);
            }
            IEnumerable enumerable = this.DataSource;
            if (enumerable != null)
            {
                IEnumerator enumerator = enumerable.GetEnumerator();
                int num = -1;
                while (enumerator.MoveNext() && (num < index))
                {
                    num++;
                    if (num == index)
                    {
                        return enumerator.Current;
                    }
                }
            }
            return null;
        }

        private SortDescription? GetSortDescriptionForGroup(string propertyName, DataGridColumnValue<DataGridSortDirection>[] sortDescriptions, List<SortDescription> currentSortDescriptions)
        {
            Func<SortDescription, bool> predicate = null;
            DataGridColumnValue<DataGridSortDirection> value2 = sortDescriptions.FirstOrDefault<DataGridColumnValue<DataGridSortDirection>>(sd => sd.Column.ActualSortMemberPath.Equals(propertyName));
            if (value2 != null)
            {
                return new SortDescription(propertyName, (((DataGridSortDirection)value2.Value) == DataGridSortDirection.Ascending) ? ListSortDirection.Ascending : ListSortDirection.Descending);
            }
            if (predicate == null)
            {
                predicate = sd => sd.PropertyName.Equals(propertyName);
            }
            SortDescription description = currentSortDescriptions.FirstOrDefault<SortDescription>(predicate);
            if (!string.IsNullOrEmpty(description.PropertyName))
            {
                return new SortDescription?(description);
            }
            return null;
        }

        private void HandleCollectionChanged(object sender, NotifyCollectionChangedEventArgs e)
        {
            if ((this.CollectionChanged != null) && (((this.GroupedFields == null) || (this.GroupedFields.Length <= 0)) || (this.Groups != null)))
            {
                this.PrintCollectionChangedEventArgs(e);
                CollectionChangedEventArgs args = this.ToCollectionChangedEventArgs(e);
                this.CollectionChanged(this, args);
            }
        }

        public int IndexOf(object dataItem)
        {
            IList list = this.List;
            if (list != null)
            {
                return list.IndexOf(dataItem);
            }
            PagedCollectionView dataSource = this.DataSource as PagedCollectionView;
            if (dataSource != null)
            {
                return dataSource.IndexOf(dataItem);
            }
            IEnumerable enumerable = this.DataSource;
            if ((enumerable != null) && (dataItem != null))
            {
                int num = 0;
                foreach (object obj2 in enumerable)
                {
                    if ((dataItem == null) && (obj2 == null))
                    {
                        return num;
                    }
                    if (dataItem.Equals(obj2))
                    {
                        return num;
                    }
                    num++;
                }
            }
            return -1;
        }

        public object InvokeGenericMethod(object owner, Type methodGenericType, string methodName, object[] methodParameterValues, Type[] methodParameterTypes)
        {
            if (methodGenericType != null)
            {
                try
                {
                    return owner.GetType().GetMethod(methodName, BindingFlags.NonPublic | BindingFlags.Instance, null, methodParameterTypes, null).MakeGenericMethod(new Type[] { methodGenericType }).Invoke(owner, methodParameterValues);
                }
                catch (TargetInvocationException exception)
                {
                    if (exception.InnerException != null)
                    {
                        throw exception.InnerException;
                    }
                    throw;
                }
            }
            throw new ArgumentNullException("type");
        }

        private object InvokeMethod(string methodName, object[] methodParameterValues, Type[] methodParameterTypes)
        {
            if (this._dataType != null)
            {
                return this.InvokeGenericMethod(this, this._dataType, methodName, methodParameterValues, methodParameterTypes);
            }
            return null;
        }

        private bool IsColumnGrouped(string propertyName)
        {
            return (this.CollectionView.GroupDescriptions.FirstOrDefault<GroupDescription>(g => ((PropertyGroupDescription)g).PropertyName.Equals(propertyName)) != null);
        }

        public bool MoveCurrentToPosition(int position)
        {
            if (this.CollectionView == null)
            {
                return false;
            }
            return this.CollectionView.MoveCurrentToPosition(position);
        }

        private void PrintCollectionChangedEventArgs(NotifyCollectionChangedEventArgs e)
        {
            if (e.Action != NotifyCollectionChangedAction.Add)
            {
                NotifyCollectionChangedAction action = e.Action;
            }
        }

        private string PrintList(IList list)
        {
            string str = "";
            foreach (object obj2 in list)
            {
                str = str + obj2.ToString();
                str = str + ",";
            }
            if (str.Length > 0)
            {
                str = str.Remove(str.Length - 1);
            }
            return str;
        }

        public void Refresh()
        {
            if (this.CollectionView != null)
            {
                this.CollectionView.Refresh();
            }
        }

        public void RemoveDataItems(int[] removedIndexes)
        {
            if (this.EditableCollectionView != null)
            {
                foreach (int num in from i in removedIndexes.Distinct<int>()
                                    orderby i descending
                                    select i)
                {
                    this.EditableCollectionView.RemoveAt(num);
                }
            }
        }

        private void SynchronizeGroupSort(GroupedField[] groupDescriptions)
        {
            int index = 0;
            GroupedField[] fieldArray = groupDescriptions;
            for (int i = 0; i < fieldArray.Length; i++)
            {
                Func<SortDescription, bool> predicate = null;
                GroupedField gd = fieldArray[i];
                if (predicate == null)
                {
                    predicate = sd => sd.PropertyName.Equals(gd.PropertyName);
                }
                foreach (SortDescription description in this.CollectionView.SortDescriptions.Where<SortDescription>(predicate).ToList<SortDescription>())
                {
                    this.CollectionView.SortDescriptions.Remove(description);
                }
                if (gd.Direction != DataGridSortDirection.None)
                {
                    ListSortDirection direction = (gd.Direction == DataGridSortDirection.Ascending) ? ListSortDirection.Ascending : ListSortDirection.Descending;
                    SortDescription item = new SortDescription(gd.PropertyName, direction);
                    this.CollectionView.SortDescriptions.Insert(index, item);
                    index++;
                }
            }
        }

        private CollectionChangedEventArgs ToCollectionChangedEventArgs(NotifyCollectionChangedEventArgs e)
        {
            Type type;
            IEnumerable<PropertyInfo> enumerable;
            Func<PropertyInfo, bool> predicate = null;
            CollectionChangedEventArgs args = new CollectionChangedEventArgs();
            if ((e.NewItems != null) && (e.NewItems.Count > 0))
            {
                KeyValuePair<int, object>[] pairArray = new KeyValuePair<int, object>[e.NewItems.Count];
                for (int i = 0; i < e.NewItems.Count; i++)
                {
                    pairArray[i] = new KeyValuePair<int, object>(e.NewStartingIndex + i, e.NewItems[i]);
                }
                args.AddedItems = pairArray;
            }
            if ((e.OldItems != null) && (e.OldItems.Count > 0))
            {
                KeyValuePair<int, object>[] pairArray2 = new KeyValuePair<int, object>[e.OldItems.Count];
                for (int j = 0; j < e.OldItems.Count; j++)
                {
                    pairArray2[j] = new KeyValuePair<int, object>(e.OldStartingIndex + j, e.OldItems[j]);
                }
                args.RemovedItems = pairArray2;
            }
            if (((this._dataSource != null) && this._dataSource.GetDataTypeAndProperties(out type, out enumerable)) && ((type != null) && (type != typeof(object))))
            {
                if ((this._dataProperties != null) && (this._dataType == type))
                {
                    if (predicate == null)
                    {
                        predicate = p => !this._dataProperties.Contains<PropertyInfo>(p);
                    }
                    if (!enumerable.Any<PropertyInfo>(predicate))
                    {
                        return args;
                    }
                }
                this._dataType = type;
                this._dataProperties = enumerable;
                args.ItemPropertiesChanged = true;
            }
            return args;
        }

        private CollectionChangedEventArgs ToC1CollectionChangedEventArgs(KeyValuePair<int, object>[] addedItems, KeyValuePair<int, object>[] removedItems)
        {
            return new CollectionChangedEventArgs { AddedItems = addedItems, RemovedItems = removedItems, ItemPropertiesChanged = false };
        }

        private DataGridColumnValue<DataGridFilterState>[] ToC1FilterDescriptions()
        {
            if (this.CollectionView.CanFilter && (this.CollectionView.Filter == this._desiredMSfilters))
            {
                return this._desiredC1filters;
            }
            return new DataGridColumnValue<DataGridFilterState>[0];
        }

        private DataGridColumnValue<DataGridSortDirection>[] ToC1SortDescriptions()
        {
            List<DataGridColumnValue<DataGridSortDirection>> list = new List<DataGridColumnValue<DataGridSortDirection>>();
            using (IEnumerator<SortDescription> enumerator = this.CollectionView.SortDescriptions.GetEnumerator())
            {
                while (enumerator.MoveNext())
                {
                    Func<DataGridColumn, bool> predicate = null;
                    SortDescription sd = enumerator.Current;
                    if (predicate == null)
                    {
                        predicate = c => c.ActualSortMemberPath == sd.PropertyName;
                    }
                    foreach (DataGridColumn column in this._owner.Columns.Where<DataGridColumn>(predicate))
                    {
                        DataGridSortDirection direction = (sd.Direction == ListSortDirection.Ascending) ? DataGridSortDirection.Ascending : DataGridSortDirection.Descending;
                        DataGridColumnValue<DataGridSortDirection> item = new DataGridColumnValue<DataGridSortDirection>(column, direction);
                        list.Add(item);
                    }
                }
            }
            return list.ToArray();
        }

        private void ToMSFilterDescriptions<T>(DataGridColumnValue<DataGridFilterState>[] filterDescriptions)
        {
            if (this.CollectionView.CanFilter)
            {
                this._desiredC1filters = filterDescriptions;
                using (this.CollectionView.DeferRefresh())
                {
                    this.CollectionView.Filter = null;
                    this._desiredMSfilters = DataGridFilterHelper.BuildFilterPredicate<T>(filterDescriptions, this._owner.FiltersCombination);
                    this.CollectionView.Filter = this._desiredMSfilters;
                }
            }
        }

        private void ToMSSortDescriptions(DataGridColumnValue<DataGridSortDirection>[] sortDescriptions)
        {
            if ((this.CollectionView != null) && this.CollectionView.CanSort)
            {
                using (this.CollectionView.DeferRefresh())
                {
                    List<SortDescription> currentSortDescriptions = this.CollectionView.SortDescriptions.ToList<SortDescription>();
                    this.CollectionView.SortDescriptions.Clear();
                    if (sortDescriptions != null)
                    {
                        foreach (DataGridColumnValue<DataGridSortDirection> value2 in sortDescriptions)
                        {
                            if (!this.IsColumnGrouped(value2.Column.ActualSortMemberPath))
                            {
                                ListSortDirection direction = (((DataGridSortDirection)value2.Value) == DataGridSortDirection.Ascending) ? ListSortDirection.Ascending : ListSortDirection.Descending;
                                SortDescription item = new SortDescription(value2.Column.ActualSortMemberPath, direction);
                                this.CollectionView.SortDescriptions.Add(item);
                            }
                        }
                        int num = 0;
                        foreach (GroupDescription description2 in this.CollectionView.GroupDescriptions)
                        {
                            SortDescription? nullable = this.GetSortDescriptionForGroup(((PropertyGroupDescription)description2).PropertyName, sortDescriptions, currentSortDescriptions);
                            if (nullable.HasValue)
                            {
                                this.CollectionView.SortDescriptions.Insert(num++, nullable.Value);
                            }
                        }
                    }
                }
            }
        }

        private void UnWireEvents(IEnumerable value)
        {
            INotifyCollectionChanged changed = value as INotifyCollectionChanged;
            if (changed != null)
            {
                changed.CollectionChanged -= new NotifyCollectionChangedEventHandler(this.HandleCollectionChanged);
            }
            if (this.CollectionView != null)
            {
                this.CollectionView.CurrentChanged -= new EventHandler(this.CollectionView_CurrentChanged);
                this.CollectionView.CurrentChanging -= new CurrentChangingEventHandler(this.CollectionView_CurrentChanging);
                SortDescriptionCollection sortDescriptions = this.CollectionView.SortDescriptions;
            }
        }

        private void WireEvents(IEnumerable value)
        {
            INotifyCollectionChanged changed = value as INotifyCollectionChanged;
            if (changed != null)
            {
                changed.CollectionChanged += new NotifyCollectionChangedEventHandler(this.HandleCollectionChanged);
            }
            if (this.CollectionView != null)
            {
                this.CollectionView.CurrentChanged += new EventHandler(this.CollectionView_CurrentChanged);
                this.CollectionView.CurrentChanging += new CurrentChangingEventHandler(this.CollectionView_CurrentChanging);
                SortDescriptionCollection sortDescriptions = this.CollectionView.SortDescriptions;
            }
        }

        // Properties
        public bool AllowAdd
        {
            get
            {
                return ((this.EditableCollectionView != null) && this.EditableCollectionView.CanAddNew);
            }
        }

        public bool AllowEdit
        {
            get
            {
                return (this.EditableCollectionView != null);
            }
        }

        public bool AllowFilter
        {
            get
            {
                return ((this.CollectionView != null) && this.CollectionView.CanFilter);
            }
        }

        public bool AllowGroup
        {
            get
            {
                return ((this.CollectionView != null) && this.CollectionView.CanGroup);
            }
        }

        public bool AllowRemove
        {
            get
            {
                return ((this.EditableCollectionView != null) && this.EditableCollectionView.CanRemove);
            }
        }

        public bool AllowSort
        {
            get
            {
                return ((this.CollectionView != null) && this.CollectionView.CanSort);
            }
        }

        public ICollectionView CollectionView
        {
            get
            {
                return (this.DataSource as ICollectionView);
            }
        }

        public int Count
        {
            get
            {
                IList list = this.List;
                if (list != null)
                {
                    return list.Count;
                }
                PagedCollectionView dataSource = this.DataSource as PagedCollectionView;
                if (dataSource != null)
                {
                    return dataSource.Count;
                }
                int num = 0;
                IEnumerable enumerable = this.DataSource;
                if (enumerable != null)
                {
                    IEnumerator enumerator = enumerable.GetEnumerator();
                    if (enumerator == null)
                    {
                        return num;
                    }
                    while (enumerator.MoveNext())
                    {
                        num++;
                    }
                }
                return num;
            }
        }

        public int CurrentPosition
        {
            get
            {
                return this.CollectionView.CurrentPosition;
            }
        }

        public bool DataIsPrimitive
        {
            get
            {
                return Extensions.DataTypeIsPrimitive(this._dataType);
            }
        }

        public PropertyInfo[] DataProperties
        {
            get
            {
                if (this._dataProperties == null)
                {
                    return null;
                }
                return this._dataProperties.ToArray<PropertyInfo>();
            }
        }

        public IEnumerable DataSource
        {
            get
            {
                return this._dataSource;
            }
            set
            {
                if (this._dataSource != null)
                {
                    this.UnWireEvents(this._dataSource);
                    this._dataSource = null;
                    this._dataProperties = null;
                    this._dataType = null;
                }
                if (value != null)
                {
                    this._dataSource = (value is ICollectionView) ? ((ICollectionView)value) : new PagedCollectionView(value);
                    this._dataSource.GetDataTypeAndProperties(out this._dataType, out this._dataProperties);
                    this.WireEvents(this._dataSource);
                }
            }
        }

        public Type DataType
        {
            get
            {
                return this._dataType;
            }
        }

        public IEditableCollectionView EditableCollectionView
        {
            get
            {
                return (this.DataSource as IEditableCollectionView);
            }
        }

        public DataGridColumnValue<DataGridFilterState>[] FilterDescriptions
        {
            get
            {
                ICollectionViewFilterExtension dataSource = this.DataSource as ICollectionViewFilterExtension;
                if (dataSource != null)
                {
                    return dataSource.FilterDescriptions;
                }
                return this.ToC1FilterDescriptions();
            }
            set
            {
                ICollectionViewFilterExtension dataSource = this.DataSource as ICollectionViewFilterExtension;
                if (dataSource != null)
                {
                    dataSource.FilterDescriptions = value;
                }
                else
                {
                    this.InvokeMethod("ToMSFilterDescriptions", new object[] { value }, new Type[] { value.GetType() });
                }
            }
        }

        public GroupedField[] GroupedFields
        {
            get
            {
                ICollectionViewGroupExtension dataSource = this.DataSource as ICollectionViewGroupExtension;
                if (dataSource != null)
                {
                    return (from pair in dataSource.GroupDescriptions select new GroupedField { PropertyName = pair.Column.ActualSortMemberPath, Direction = pair.Value }).ToArray<GroupedField>();
                }
                if (!this.CollectionView.CanGroup)
                {
                    return new GroupedField[0];
                }
                List<GroupedField> list = new List<GroupedField>(this.CollectionView.GroupDescriptions.Count);
                using (IEnumerator<GroupDescription> enumerator = this.CollectionView.GroupDescriptions.GetEnumerator())
                {
                    while (enumerator.MoveNext())
                    {
                        Func<SortDescription?, bool> predicate = null;
                        PropertyGroupDescription gd = (PropertyGroupDescription)enumerator.Current;
                        if (predicate == null)
                        {
                            predicate = sd => sd.Value.PropertyName.Equals(gd.PropertyName);
                        }
                        SortDescription? nullable = this.CollectionView.SortDescriptions.Cast<SortDescription?>().FirstOrDefault<SortDescription?>(predicate);
                        DataGridSortDirection none = DataGridSortDirection.None;
                        if (nullable.HasValue)
                        {
                            none = (nullable.Value.Direction == ListSortDirection.Ascending) ? DataGridSortDirection.Ascending : DataGridSortDirection.Descending;
                        }
                        GroupedField item = new GroupedField
                        {
                            PropertyName = gd.PropertyName,
                            Direction = none
                        };
                        list.Add(item);
                    }
                }
                return list.ToArray();
            }
            set
            {
                ICollectionViewGroupExtension dataSource = this.DataSource as ICollectionViewGroupExtension;
                if (dataSource != null)
                {
                    List<DataGridColumnValue<DataGridSortDirection>> list = new List<DataGridColumnValue<DataGridSortDirection>>();
                    GroupedField[] fieldArray = value;
                    for (int i = 0; i < fieldArray.Length; i++)
                    {
                        Func<DataGridColumn, bool> predicate = null;
                        GroupedField gd = fieldArray[i];
                        if (predicate == null)
                        {
                            predicate = c => c.ActualSortMemberPath == gd.PropertyName;
                        }
                        DataGridColumn column = this._owner.Columns.FirstOrDefault<DataGridColumn>(predicate);
                        if (column != null)
                        {
                            list.Add(new DataGridColumnValue<DataGridSortDirection>(column, gd.Direction));
                        }
                    }
                    dataSource.GroupDescriptions = list.ToArray();
                }
                else if ((this.CollectionView != null) && this.CollectionView.CanGroup)
                {
                    using (this.CollectionView.DeferRefresh())
                    {
                        this.CollectionView.GroupDescriptions.Clear();
                        if (value != null)
                        {
                            this.SynchronizeGroupSort(value);
                            foreach (GroupedField field in value)
                            {
                                if (field.GroupConverter == null)
                                {
                                    this.CollectionView.GroupDescriptions.Add(new PropertyGroupDescription(field.PropertyName));
                                }
                                else
                                {
                                    this.CollectionView.GroupDescriptions.Add(new PropertyGroupDescription(field.PropertyName, field.GroupConverter));
                                }
                            }
                        }
                    }
                }
            }
        }

        public ReadOnlyObservableCollection<object> Groups
        {
            get
            {
                return this.CollectionView.Groups;
            }
        }

        public IList List
        {
            get
            {
                return (this.DataSource as IList);
            }
        }

        public DataGridColumnValue<DataGridSortDirection>[] SortDescriptions
        {
            get
            {
                ICollectionViewSortExtension dataSource = this.DataSource as ICollectionViewSortExtension;
                if (dataSource != null)
                {
                    return dataSource.SortDescriptions;
                }
                return this.ToC1SortDescriptions();
            }
            set
            {
                ICollectionViewSortExtension dataSource = this.DataSource as ICollectionViewSortExtension;
                if (dataSource != null)
                {
                    dataSource.SortDescriptions = value;
                }
                else
                {
                    this.ToMSSortDescriptions(value);
                }
            }
        }
    }
}
